<template>
  <div class="roleTree">
    <el-collapse class="collapseBox" v-model="activeNameArr">
      <el-collapse-item v-for="(item, index) in treeData" :key="index" :disabled="isDisabled(item)" :name="item._id">
        <template slot="title">
          <el-checkbox
            :disabled="item.disable"
            :style="{marginLeft: item.parentId ? treeLevelNum * 50 + 'px' : '10px'}"
            :label="item._id"
            v-model="item.checked"
            @change="checkboxFun">
            {{item.name}}
          </el-checkbox>
        </template>
        <roleTree v-if="item.children && item.children.length > 0" :parentData="item" :treeData="item.children" :treeLevelNum="treeLevelNum + 1"></roleTree>
        <div class="dataContent" :style="{marginLeft: treeLevelNum * 65 + 'px'}" v-if="(item.scope && item.scope.length > 0) || item.function">
          <div class="dataAuthorityBox" v-if="item.scope && item.scope.length > 0">
            <span class="labelTitle">数据权限：</span>
            <m7Select style="width:200px" filterable size="mini" v-model="checkedForm.scope[item._id]" @input="selectChangeFun($event, item.scope)" placeholder="请选择" :options="item.scope" :defaultProps="{value: '_id', label:'name'}">
            </m7Select>
          </div>
          <div :class="item.parentId ? '' : 'functionAuthorityBox'" v-if="item.function && item.function.length > 0">
            <span class="labelTitle">功能权限：</span>
            <el-checkbox :indeterminate="checkedForm.isIndeterminate[item._id]"
              v-model="checkedForm.allChecked[item._id]"
              @change="handleCheckAllChange($event, {arr: item.function, _id: item._id})">
              全选
            </el-checkbox>
            <el-checkbox-group v-model="checkedForm[item._id]"
               @change="handleCheckedChange($event, {arr: item.function, _id: item._id})"
               class="checkboxGroup">
              <el-checkbox v-for="(funItem, index) in item.function" :label="funItem._id" :key="index">{{funItem.name}}</el-checkbox>
            </el-checkbox-group>
          </div>
        </div>
      </el-collapse-item>
    </el-collapse>
  </div>
</template>
<script lang="ts">
import { Component, Vue, Prop, Watch } from 'vue-property-decorator'
function chooseData (data, checkedId, checkedStatus, once ?: any) { // 处理当前被选中的状态
  for (let i = 0; i < data.length; i++) {
    if (once) { // 当前层级被选中的状态处理
      if (checkedStatus) {
        data[i].checked = true
      } else {
        data[i].checked = false
      }
      if (data[i].children && data[i].children.length > 0) {
        chooseData(data[i].children, checkedId, checkedStatus, 'two')
      }
    } else { // 子集被选中的状态处理
      if (data[i]._id === checkedId) {
        if (checkedStatus) {
          data[i].checked = true
        } else {
          data[i].checked = false
        }
        if (data[i].children && data[i].children.length > 0) {
          chooseData(data[i].children, checkedId, checkedStatus, 'two')
        }
      }
    }
  }
}
interface ArrayObj {
  props: string
}
@Component({
  name: 'roleTree'
})
export default class RoleTree extends Vue {
  [x: string]: any
  @Prop(Array) public treeData!: ArrayObj[]
  @Prop(Object) public parentData!: any
  @Prop(Number) public treeLevelNum!: any

  private chooseArray: any = []

  private checkedForm = {
    isIndeterminate: {},
    allChecked: {},
    scope: {}
  }

  private activeNameArr: any = []

  private handleCheckAllChange ($event, obj) { // 功能权限全选处理
    const checkedArr: any = []
    obj.arr.forEach((item: any) => {
      if ($event) {
        item.checked = true
        checkedArr.push(item._id)
        this.checkedForm[obj._id] = checkedArr
      } else {
        item.checked = false
        this.checkedForm[obj._id] = []
      }
    })

    this.checkedForm.isIndeterminate[obj._id] = false
  }

  private handleCheckedChange ($event, obj) { // 功能权限勾选处理
    obj.arr.forEach(item => {
      if ($event.indexOf(item._id) > -1) {
        item.checked = true
      } else {
        item.checked = false
      }
    })
    const checkedCount = $event.length
    this.checkedForm.allChecked[obj._id] = checkedCount === obj.arr.length
    this.checkedForm.isIndeterminate[obj._id] = checkedCount > 0 && checkedCount < obj.arr.length
  }

  private ativeName () { // 初始化需要展开的数据处理
    this.treeData.forEach((item: any) => {
      this.activeNameArr.push(item._id)
    })
  }

  private isDisabled (item) { // 是否可以展开处理
    if ((!item.children || item.children.length === 0) && !((item.scope && item.scope.length > 0) || (item.funAuthority && item.funAuthority.length > 0))) {
      return true
    } else {
      return false
    }
  }

  private checkboxFun (val, event) { // 当前被选中的权限事件
    const chooseId = event.target.value
    const checked = val
    // 父级
    const fatherTag: any = this.treeData.find((item: any) => {
      return item._id === chooseId
    })
    const childrenArr = fatherTag.children || []
    // 选中
    if (checked) {
      if (childrenArr.length > 0) {
        childrenArr.forEach((child: any) => {
          child.checked = true
        })
      }
      this.$bus.$emit('currentChooseFun', chooseId, true)
    } else { // 取消选中
      if (childrenArr.length > 0) {
        childrenArr.forEach((child: any) => {
          child.checked = false
        })
      }
      this.$bus.$emit('currentChooseFun', chooseId, false)
    }
    this.treeData.forEach((item: any) => { // 当前被选中的数据处理
      if (item.checked) {
        if (this.chooseArray.indexOf(item._id) === -1) {
          this.chooseArray.push(item._id)
        }
      } else {
        if (this.chooseArray.indexOf(item._id) !== -1) {
          this.chooseArray.splice(this.chooseArray.indexOf(item._id), 1)
        }
      }
    })
    if (this.parentData) { // 外抛父级的处理
      if (this.chooseArray.length > 0 || this.chooseArray.length === this.parentData.children.length) { // 当前层级有一个被选中或者全被选中通知父级需要勾选
        this.$bus.$emit('childChooseFun', this.parentData._id, true)
      } else if (this.chooseArray.length === 0) { // 当前层级一个没有被选中通知父级取消勾选
        this.$bus.$emit('childChooseFun', this.parentData._id, false)
      }
    }
  }

  private selectChangeFun ($event, option) { // 数据权限下拉事件处理
    option.forEach(item => {
      if ($event === item._id) {
        item.checked = true
      } else {
        item.checked = false
      }
    })
  }

  private handleCheckedLength (data: any) { // 处理当前级是否选中
    let chooseArrayLength = 0
    data.forEach((parentItem: any) => {
      if (parentItem.checked) {
        chooseArrayLength = chooseArrayLength + 1
      }
    })
    return chooseArrayLength
  }

  private beforeDestroy () {
    this.$bus.$off('childChooseFun')
    this.$bus.$off('currentChooseFun')
  }

  private initData () {
    this.treeData.forEach((item: any) => {
      if (item.function && item.function.length > 0) {
        this.$set(this.checkedForm, item._id, [])
        let checkedCount = 0
        item.function.forEach((functionItem: any) => { // 功能权限的初始化处理
          if (functionItem.checked) {
            checkedCount++
            this.checkedForm[item._id].push(functionItem._id)
          }
        })
        if (checkedCount === item.function.length) { // 功能权限是否全选
          this.$set(this.checkedForm.allChecked, item._id, true)
        } else {
          this.$set(this.checkedForm.allChecked, item._id, false)
        }
        if (checkedCount > 0 && checkedCount < item.function.length) {
          this.$set(this.checkedForm.isIndeterminate, item._id, true)
        } else {
          this.$set(this.checkedForm.isIndeterminate, item._id, false)
        }
      }
      if (item.scope && item.scope.length > 0) { // 数据权限初始化处理
        item.scope.forEach(scopeItem => {
          if (scopeItem.checked) {
            this.$set(this.checkedForm.scope, item._id, scopeItem._id)
          }
        })
      }
    })
  }

  private beforeMount () {
    // 初始化数据
    this.initData()
  }

  @Watch('treeData')
  private treeDataChange () {
    this.initData()
    this.$nextTick(() => {
      this.ativeName()
    })
  }

  private mounted () {
    this.$nextTick(() => {
      this.ativeName()
    })
    this.$bus.$on('childChooseFun', (parentId, isChecked) => { // 层级倒序处理
      this.treeData.forEach((item: any, index) => {
        if (item._id === parentId) {
          if (!item.parentId) { // 第一级
            const len = this.handleCheckedLength(item.children)
            if (len === 0) { // 二级都没有选中
              item.checked = false
            } else { // 二级选中 > 0
              item.checked = true
            }
          } else { // 非第一级的处理
            const len2 = this.handleCheckedLength(item.children)
            if (item.parentId && item.parentId !== '') { // 有父级
              if (len2 === 0) { // 当前级的都没选中，外抛告诉父级，变成没选中
                item.checked = false
                this.$bus.$emit('childChooseFun', item.parentId, false)
              } else { // 当前级的只要有一个选中，父级就是选中
                item.checked = true
                this.$bus.$emit('childChooseFun', item.parentId, true)
              }
            }
          }
        }
      })
    })
    this.$bus.$on('currentChooseFun', (res, isChecked) => { // 当前被选中的子集外抛事件
      chooseData(this.treeData, res, isChecked)
    })
  }
}
</script>
<style lang="stylus" scoped>
  .collapseBox
    // border 1px solid $border-main
  .dataContent
    margin 10px 0px 10px 50px
  .labelTitle
    font-size 12px
  .checkboxGroup
    margin 10px 0px
  .dataAuthorityBox
    margin 0px 0px 10px 10px
  .functionAuthorityBox
    margin-left 30px
</style>
<style lang="stylus">
  .roleTree
    .el-checkbox__label
      font-size 12px
    .el-checkbox__inner
      width 12px
      height 12px
    .el-checkbox__input.is-indeterminate .el-checkbox__inner::before
      top 4px
    .el-checkbox__inner::after
      height 5px
      top 1px
      left 3px
    .el-collapse-item__content
      padding 0px
    .el-collapse
      border-bottom none
</style>
